package http

import (
	"gitee.com/captials-team/ubdframe/src/common"
	"gitee.com/captials-team/ubdframe/src/common/consts"
	"gitee.com/captials-team/ubdframe/src/common/utils"
	"gitee.com/captials-team/ubdframe/src/domain/configstc"
	"gitee.com/captials-team/ubdframe/src/domain/dto"
	"gitee.com/captials-team/ubdframe/src/domain/dto/paginate"
	"gitee.com/captials-team/ubdframe/src/domain/dto/reqdata"
	"gitee.com/captials-team/ubdframe/src/domain/dto/respdata"
	"gitee.com/captials-team/ubdframe/src/domain/interfaces"
	"gitee.com/captials-team/ubdframe/src/domain/models"
	"gitee.com/captials-team/ubdframe/src/pkg/gin_http"
	"gitee.com/captials-team/ubdframe/src/pkg/i18n"
	v1log "gitee.com/captials-team/ubdframe/src/pkg/logs"
	"gitee.com/captials-team/ubdframe/src/pkg/passwd"
	"gitee.com/captials-team/ubdframe/src/resource"
	"github.com/gin-gonic/gin"
	"go.uber.org/dig"
	"golang.org/x/text/language"
	"net/http"
)

type AdminController struct {
	l v1log.ILog

	adminModel    interfaces.ItfAdminDao
	adminLogModel interfaces.ItfAdminLog

	conf *configstc.AdminAppConfig

	*gin_http.I18nController
	passwd.SaltMd5Password
	passwd.StrongPasswordChecker
}

func NewAdminController(di *dig.Scope, l v1log.ILog, conf *configstc.AdminAppConfig) *AdminController {
	ctr := &AdminController{
		l: l,

		conf: conf,
	}

	common.ErrPanic(di.Invoke(func(admin interfaces.ItfAdminDao, adminLog interfaces.ItfAdminLog) {
		ctr.adminModel = admin
		ctr.adminLogModel = adminLog
	}))

	//i18n
	ctr.initI18n()

	//初始化账户
	ctr.initAccount()

	return ctr
}

func (ctr *AdminController) initI18n() {
	parser := i18n.NewParser()

	//从本地加载指定的i18n文件
	common.ErrPanic(utils.ScanEmbedFsDo(resource.I18nFs, func(file string, path string) error {
		content, err := resource.I18nFs.ReadFile(path)
		common.ErrPanic(err)

		parser.Bundle().MustParseMessageFileBytes(content, file)

		//file文件名必须对应上 language.English.String()
		//ctr.l.Info("File=%s", file)
		//ctr.l.Info("English=%s", language.English.String())
		//ctr.l.Info("Chinese=%s", language.Chinese.String())

		return nil
	}))

	//parser.Bundle().MustParseMessageFileBytes([]byte(``), language.Chinese.String()+".toml")

	for name, path := range ctr.conf.I18nFiles {
		parser.Load(path, name+".toml")
		//ctr.l.Info("load i18n path %s: %s, %s", name, path, parser.Lang(name).ParseMsg("Hello"))
	}
	parser.SetLanguage(language.Chinese)
	parser.CacheLanguages()
	ctr.I18nController = &gin_http.I18nController{
		Parser: parser,
	}
}

func (ctr *AdminController) initAccount() {
	var err error
	//自动创建admin账户
	if ctr.conf.AutoCreateAdmin {
		salt := utils.RandLetterFigureCode(16)
		_, err = ctr.adminModel.AddCheckAccount(&models.Admin{
			Id:       0,
			Account:  "admin",
			Password: passwd.GenSaltPasswordByMd5("123456", salt),
			Salt:     salt,
			Nickname: "超级管理员",
			Avatar:   "",
			Email:    "system@system.com",
			IsRoot:   consts.StatusTrue,
			Status:   consts.StatusEnable,
		})
		common.ErrPanic(err)
		ctr.l.Info("add SuperAdmin success")
	}
}

// SearchAdmin godoc
// @Summary      管理员管理-搜索列表
// @Description  搜索管理员列表
// @Tags         admin
// @Security     AdminKeyAuth
// @Produce      json
// @Param        param    body     reqdata.SearchAdminReq  true  "搜索参数集"
// @success 0  {object} respdata.ResponseData{data=respdata.SearchListResponse{list=[]models.Admin}} "获取成功"
// @Router       /mag/admin/search [post]
func (ctr *AdminController) SearchAdmin(ctx *gin.Context) {
	auth := gin_http.GetAuth(ctx)

	var req reqdata.SearchAdminReq
	ctx.ShouldBind(&req)

	params := &dto.SearchAdminParams{
		Keywords: req.Keywords,
		Status:   req.Status,
	}

	if configstc.CommonExtendParams(auth.Extends).ExtendParamByBool("is_root") {
		params.IsRoot = -1
	}

	list, pager, err := ctr.adminModel.Search(params, &paginate.Pager{
		Page: req.Page,
		Size: req.Size,
	})
	if err != nil {
		ctr.l.Error("search err %s", err)
		ctr.Response(ctx, respdata.CSysBusy)
		return
	}

	ctr.Response(ctx, respdata.CSuccess.MData(respdata.SearchListResponse{
		List:     utils.CopyMoreTo(list, []*respdata.AdminListItemResp{}),
		Paginate: *pager,
	}))
}

// QueryAdmin godoc
// @Summary      管理员管理-查看详请
// @Description  获取管理员详细信息
// @Security     AdminKeyAuth
// @Tags         admin
// @Accept       json
// @Produce      json
// @Param        param    body     reqdata.DetailReq  true  "查询指定id详情"
// @success 0  {object} respdata.ResponseData{data=respdata.AdminDetailResp} "获取成功"
// @failure 2  {object} respdata.ResponseData{} "系统错误"
// @failure 4  {object} respdata.ResponseData{} "参数错误"
// @failure 8  {object} respdata.ResponseData{} "操作失败"
// @Router       /mag/admin/detail [post]
func (ctr *AdminController) QueryAdmin(ctx *gin.Context) {
	var req reqdata.DetailReq

	ctx.ShouldBind(&req)
	if req.Id <= 0 {
		ctr.Response(ctx, respdata.CParamsInvalid)
		return
	}

	data, err := ctr.adminModel.Query(req.Id)
	if err != nil {
		ctr.Response(ctx, respdata.CSysBusy)
		return
	}
	if data == nil {
		ctr.Response(ctx, respdata.CNotFound)
		return
	}

	ctr.Response(ctx, respdata.CSuccess.MData(utils.CopyTo(data, new(respdata.AdminDetailResp))))
}

// SaveAdmin godoc
// @Summary      管理员管理-新增/更新
// @Description  新增管理员，编辑提交管理员
// @Security     AdminKeyAuth
// @Tags         admin
// @Accept       json
// @Produce      json
// @Param        param    body     reqdata.AddEditAdminReq  true  "新增/编辑信息"
// @success 0  {object} respdata.ResponseData{data=models.Admin} "处理成功"
// @failure 2  {object} respdata.ResponseData{} "系统错误"
// @failure 4  {object} respdata.ResponseData{} "参数错误"
// @failure 8  {object} respdata.ResponseData{} "操作失败"
// @Router       /mag/admin/save [post]
func (ctr *AdminController) SaveAdmin(ctx *gin.Context) {
	var req reqdata.AddEditAdminReq

	ctx.ShouldBind(&req)

	if req.Nickname == "" {
		ctr.Response(ctx, respdata.CParamsInvalid)
		return
	}
	if req.Id == 0 && (req.Account == "" || req.Password == "") {
		ctr.Response(ctx, respdata.CParamsInvalid)
		return
	}
	//新增时进行账户检查
	if req.Id == 0 {
		ctr.createAdmin(ctx, req)
	} else {
		ctr.updateAdmin(ctx, req)
	}
}

func (ctr *AdminController) createAdmin(ctx *gin.Context, req reqdata.AddEditAdminReq) {
	if req.Account == "" || req.Password == "" {
		ctr.Response(ctx, respdata.CParamsInvalid)
		return
	}
	find, err := ctr.adminModel.QueryByAccount(req.Account)
	if err != nil {
		ctr.l.Error("query fail %s", err)
		ctr.Response(ctx, respdata.CSysBusy)
		return
	}
	if find != nil {
		ctr.Response(ctx, respdata.CError.MMsg("AccountExist"))
		return
	}

	if ok, s := ctr.CheckPassword(req.Password); !ok {
		ctr.Response(ctx, respdata.CError.MMsg(s))
		return
	}

	var salt = utils.RandLetterFigureCode(16)
	req.Password = ctr.GenPassword(req.Password, salt)

	data := models.Admin{
		Account:  req.Account,
		Password: req.Password,
		Salt:     salt,

		Nickname:  req.Nickname,
		Avatar:    req.Avatar,
		Email:     req.Email,
		Phone:     req.Phone,
		Status:    req.Status,
		Remark:    req.Remark,
		ExpiredAt: req.ExpiredAt,
	}

	_, err = ctr.adminModel.Add(&data)
	if err != nil {
		ctr.l.Error("operate fail %s", err)
		ctr.Response(ctx, respdata.CFail)
		return
	}

	ctr.Response(ctx, respdata.CSuccess.MData(utils.CopyTo(&data, new(respdata.AdminDetailResp))))
}

func (ctr *AdminController) updateAdmin(ctx *gin.Context, req reqdata.AddEditAdminReq) {
	find, err := ctr.adminModel.Query(req.Id)
	if err != nil {
		ctr.l.Error("query fail %s", err)
		ctr.Response(ctx, respdata.CSysBusy)
		return
	}
	if find == nil {
		ctr.Response(ctx, respdata.CError.MMsg("AccountNotExist"))
		return
	}

	if req.Password != "" {
		if ok, s := ctr.CheckPassword(req.Password); !ok {
			ctr.Response(ctx, respdata.CError.MMsg(s))
			return
		}
		req.Password = passwd.GenSaltPasswordByMd5(req.Password, find.Salt)
	}

	data := models.Admin{
		Password: req.Password,

		Nickname:  req.Nickname,
		Avatar:    req.Avatar,
		Email:     req.Email,
		Phone:     req.Phone,
		Status:    req.Status,
		Remark:    req.Remark,
		ExpiredAt: req.ExpiredAt,
	}
	_, err = ctr.adminModel.Update(req.Id, &data)

	if err != nil {
		ctr.l.Error("operate fail %s", err)
		ctr.Response(ctx, respdata.CFail)
		return
	}

	ctr.Response(ctx, respdata.CSuccess.MData(utils.CopyTo(&data, new(respdata.AdminDetailResp))))
}

// DisableAdmin godoc
// @Summary      管理员管理-启用/禁用
// @Description  操作启用/禁用管理员
// @Security     AdminKeyAuth
// @Tags         admin
// @Accept       json
// @Produce      json
// @Param        param    body     reqdata.SetStatusReq  true  "状态设置请求"
// @success 200  {object} respdata.ResponseData{} "设置成功"
// @Router       /mag/admin/disable [post]
func (ctr *AdminController) DisableAdmin(ctx *gin.Context) {
	var req reqdata.SetStatusReq

	ctx.ShouldBind(&req)

	if req.Status != consts.StatusEnable && req.Status != consts.StatusDisable {
		ctr.Response(ctx, respdata.CParamsInvalid)
		return
	}
	admin, err := ctr.adminModel.Query(req.Id)
	if err != nil {
		ctr.l.Error("operate fail %s", err)
		ctr.Response(ctx, respdata.CSysBusy)
		return
	}
	if admin == nil {
		ctr.Response(ctx, respdata.CNotFound)
		return
	}
	if admin.IsRoot > 0 {
		ctr.Response(ctx, respdata.CError.MMsg("无法被修改"))
		return
	}
	_, err = ctr.adminModel.ResetStatus(req.Id, req.Status)
	if err != nil {
		ctr.l.Error("operate fail %s", err)
		ctr.Response(ctx, respdata.CSysBusy)
		return
	}

	ctr.Response(ctx, respdata.CSuccess)
	return
}

// DeleteAdmin godoc
// @Summary      管理员管理-删除管理员
// @Description  删除管理员
// @Security     AdminKeyAuth
// @Tags         admin
// @Accept       json
// @Produce      json
// @Param        param    body     reqdata.DetailReq  true  "指定管理员id"
// @success 200  {object} respdata.ResponseData{} "操作成功"
// @Router       /mag/admin/delete [post]
func (ctr *AdminController) DeleteAdmin(ctx *gin.Context) {
	var req reqdata.DetailReq

	ctx.ShouldBind(&req)
	if req.Id <= 0 {
		ctr.Response(ctx, respdata.CParamsInvalid)
		return
	}

	data, err := ctr.adminModel.Query(req.Id)
	if err != nil {
		ctr.Response(ctx, respdata.CSysBusy)
		return
	}
	if data == nil {
		ctr.Response(ctx, respdata.CNotFound)
		return
	}

	if _, err := ctr.adminModel.Delete(data.Id); err != nil {
		ctr.l.Error("delete admin fail %s", err)
		ctr.Response(ctx, respdata.CSysBusy)
		return
	}

	ctr.Response(ctx, respdata.CSuccess.MData(data))
}

// ModifyInfo godoc
// @Summary      账户中心-修改个人信息
// @Description  修改个人信息
// @Tags         admin.center
// @Produce      json
// @Security     AdminKeyAuth
// @Param        param    body    reqdata.ModifyInfoReq   false  "用户信息"
// @success 0  {object} respdata.ResponseData{} "成功"
// @failure 2 {object} respdata.ResponseData{} "修改失败"
// @Router       /mag/u_center/modify_info [post]
func (ctr *AdminController) ModifyInfo(ctx *gin.Context) {
	var req reqdata.ModifyInfoReq
	ctx.ShouldBind(&req)

	if req.Nickname == "" {
		ctr.Response(ctx, respdata.CParamsInvalid)
		return
	}

	auth := gin_http.GetAuth(ctx)
	if _, err := ctr.adminModel.UpdateProInfo(auth.Id, &models.Admin{
		Avatar:   req.Avatar,
		Nickname: req.Nickname,
	}); err != nil {
		ctr.l.Error("modify err %s", err)
		ctr.Response(ctx, respdata.CSysBusy)
		return
	}

	ctr.Response(ctx, respdata.CSuccess)
}

// ModifyPassword godoc
// @Summary      账户中心-修改密码
// @Description  修改密码
// @Tags         admin.center
// @Produce      json
// @Security     AdminKeyAuth
// @Param        param    body    reqdata.ModifyPasswordReq   false  "提价"
// @success 0  {object} respdata.ResponseData{} "成功"
// @failure 2 {object} respdata.ResponseData{} "修改失败"
// @Router       /mag/u_center/modify_pwd [post]
func (ctr *AdminController) ModifyPassword(ctx *gin.Context) {
	var req reqdata.ModifyPasswordReq
	ctx.ShouldBind(&req)

	if req.OldPassword == "" || req.Password == "" {
		ctr.Response(ctx, respdata.CParamsInvalid)
		return
	}
	if ok, s := ctr.CheckPassword(req.Password); !ok {
		ctr.Response(ctx, respdata.CError.MMsg(s))
		return
	}

	auth := gin_http.GetAuth(ctx)
	password, salt, err := ctr.adminModel.QueryPassword(auth.Id)
	if err != nil {
		ctr.l.Error("query fail %s", err)
		ctr.Response(ctx, respdata.CError)
		return
	}

	if password != passwd.GenSaltPasswordByMd5(req.OldPassword, salt) {
		ctr.Response(ctx, respdata.CError.MMsg("PasswordWrong"))
		return
	}

	isRoot := configstc.CommonExtendParams(auth.Extends).ExtendParamByBool("is_root")
	if _, err := ctr.adminModel.ResetPassword(auth.Id, passwd.GenSaltPasswordByMd5(req.Password, salt), isRoot); err != nil {
		ctr.Response(ctx, respdata.CSysBusy)
		return
	}

	ctr.Response(ctx, respdata.CSuccess)
}

func (ctr *AdminController) ResetPassword(ctx *gin.Context) {
	ctr.Response(ctx, respdata.CNotSupport)
} //重置密码

func (ctr *AdminController) BindEmailPhone(ctx *gin.Context) {
	ctr.Response(ctx, respdata.CNotSupport)
} //绑定邮箱

func (ctr *AdminController) LoginRecord(ctx *gin.Context) {
	ctr.Response(ctx, respdata.CNotSupport)
} //登录记录

// UserInfo godoc
// @Summary      用户信息
// @Description  用户信息，比AuthInfo提供信息更详细
// @Tags         admin.center
// @Produce      json
// @Security     ApiKeyAuth
// @success 0  {object} respdata.ResponseData{data=respdata.AdminDetailResp} "获取成功"
// @success 0  {object} respdata.ResponseData{} "重置成功"
// @fail 1 {object} respdata.ResponseData{} "重置失败"
// @Router       /mag/u_center/info [post]
func (ctr *AdminController) UserInfo(ctx *gin.Context) {
	auth := gin_http.GetAuth(ctx)
	user, err := ctr.adminModel.Query(auth.Id)
	if err != nil {
		ctr.l.Error("query fail %s", err)
		ctx.JSON(http.StatusOK, respdata.CError.MMsg("query err"))
		return
	}
	if user == nil {
		ctx.JSON(http.StatusOK, respdata.CNotFound)
		return
	}

	resp := utils.CopyTo(user, new(respdata.AdminDetailResp))
	ctr.Response(ctx, respdata.CSuccess.MData(resp))
}
